using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace BardsTaleViewer {
  public class AnimFrame_Amiga_Bard2 : IAnimFrame {
    public int _pictureIndex;
    public int _frameIndex;
    public int _animIndex;

    public int _delay;
    public Dictionary<int, List<long>> _lines;
    public Bitmap _bitmapDiff;

    public AnimFrame_Amiga_Bard2 (byte [] dump, int offset, int pictureIndex, int animIndex, int frameIndex, int delay) {
      _pictureIndex = pictureIndex;
      _animIndex = animIndex;
      _frameIndex = frameIndex;

      _delay = delay;
      _lines = new Dictionary<int, List<long>> ();
      while ((dump.ReadWord (offset) != 0xFFFF) &&
             (dump.ReadWord (offset) != 0x0000)) {
        int lineData = dump.ReadWord (ref offset);
        int nbPackets = (lineData >> 13) + 1;
        int lineOffset = lineData & 0x1FFF;
        List<long> linePixels = new List<long> ();
        for (int i = 0; i < nbPackets; i++) {
          linePixels.Add (dump.ReadLong (ref offset));
        }
        //Console.WriteLine ("0x{0:X4} Offset: 0x{1:X4}", offset - 6, lineOffset);
        _lines.Add (lineOffset, linePixels);
      }
    }

    public void CreateBitmap (Palette palette, byte [] data) {
      Point min = new Point (int.MaxValue, int.MaxValue);
      byte [] mask = new byte [112 * 88 / 8];
      mask.Init (0xFF);
      foreach (KeyValuePair<int, List<long>> kvp in _lines) {
        int lineOffset = kvp.Key;
        foreach (long linePixels in kvp.Value) {
          //long linePixels = kvp.Value;

          Point xy = OffsetToXY (lineOffset);
          //if (xy.X < min.X)
          //  min.X = xy.X;
          //if (xy.Y < min.Y)
          //  min.Y = xy.Y;
          // amiga bug
          if (xy.Y == 88)
            throw new Exception ();
          int offset = (xy.Y * 112 / 8) + (xy.X / 8);
          byte b1 = (byte) ((linePixels >> 24) & 0xFF);
          byte b2 = (byte) ((linePixels >> 16) & 0xFF);
          byte b3 = (byte) ((linePixels >> 08) & 0xFF);
          byte b4 = (byte) ((linePixels >> 00) & 0xFF);
          data [offset + (0 * 112 * 88 / 8)] ^= b1;
          data [offset + (1 * 112 * 88 / 8)] ^= b2;
          data [offset + (2 * 112 * 88 / 8)] ^= b3;
          data [offset + (3 * 112 * 88 / 8)] ^= b4;

          byte maskByte = (byte) (b1 | b2 | b3 | b4);
          mask [xy.Y * (112 / 8) + xy.X / 8] &= (byte) (maskByte ^ 0xFF);
          lineOffset++;
        }
      }
      _bitmapDiff = SpriteReader.CreateBitmap (data, 0, 112, 88, 4, SpriteReader.ModesEnum.Planar, -1, palette, 0, SpriteReader.MasksEnum.Opaque);
      _bitmapDiff.ApplyMask (mask);
      //_bitmapDiff.Save (string.Format ("Picture {0} Amiga A{1:X2} F{2:X2}.png", _pictureIndex.ToString ().PadLeft (2, '0'), _animIndex, _frameIndex), ImageFormat.Png);
    }

    private static int _offsetScreen = 1 * (15 * 320 + 16) / 8;
    private static Point OffsetToXY (int offset) {
      offset -= _offsetScreen;
      int x = (offset % 40) * 8;
      int y = offset / 40;
      //if ((x % 8) != 0)
      //  throw new Exception ();
      if ((x < 112) && (y == 88))
        x = x;
      //Console.WriteLine ("Amiga x: {0}, y: {1}", x, y);
      else
        if ((x >= 112) || (y >= 88)) {
          throw new Exception ();
          //Console.WriteLine ("Amiga x: {0}, y: {1}", x, y);
          //y = 0;
        }
      return (new Point (x, y));
    }

    public Bitmap BitmapDiff {
      get {
        return (_bitmapDiff);
      }
    }

    public int Delay {
      get {
        return (_delay);
      }
    }

    public int AnimIndex {
      get {
        return (_animIndex);
      }
    }
  }
}
